#ifndef ARRAY_H
#define ARRAY_H

#include <iostream>
using std::ostream;
using std::istream;
using std::cerr;
using std::cout;
using std::cin;
using std::endl;

#include <iomanip>
using std::setw;

#include <cstdlib> // exit function prototype
using std::exit;

template < class T, size_t size >
class Array;

template < class T, size_t size >
ostream &operator<<( ostream &, const Array< T, size > & );
template < class T, size_t size >
istream &operator>>( istream &, Array< T, size > & );

template < class T, size_t size >
class Array
{
   friend ostream &operator<< < T, size>
                ( ostream &, const Array< T, size >& );
   friend istream &operator>> < T, size>
                ( istream &, Array< T, size >& );
public:
   Array(); // default constructor

   bool operator==( const Array< T, size >& ) const; // equality operator
   bool operator!=( const Array< T, size >&right ) const  
   { 
      return ! ( *this == right ); // invokes Array::operator==
   } // end function operator!=
   
   T &operator[]( int );              
   T operator[]( int ) const;  

private:
   T ptr [size]; // pointer to first element of pointer-based array
}; // end class Array

template < class T, size_t size >
Array< T, size >::Array()
{
   for ( int i = 0; i < size; i++ )
      ptr[ i ] = 0; // set pointer-based array element
} // end Array< T, size >default constructor

template < class T, size_t size >
bool Array< T, size >::operator==( const Array< T, size >&right ) const
{
   for ( int i = 0; i < size; i++ )
      if ( ptr[ i ] != right.ptr[ i ] )
         return false; // Array< T, size >contents are not equal

   return true; // Arrays are equal
} // end function operator==

template < class T, size_t size >
T &Array< T, size >::operator[]( int subscript )
{
   if ( subscript < 0 || subscript >= size )
   {
      cerr << "\nError: Subscript " << subscript 
         << " out of range" << endl;
      exit( 1 ); // terminate program; subscript out of range
   } // end if

   return ptr[ subscript ]; // reference return
} // end function operator[]

template < class T, size_t size >
T Array< T, size >::operator[]( int subscript ) const
{
   if ( subscript < 0 || subscript >= size )
   {
      cerr << "\nError: Subscript " << subscript 
         << " out of range" << endl;
      exit( 1 ); // terminate program; subscript out of range
   } // end if

   return ptr[ subscript ]; // returns copy of this element
} // end function operator[]

template < class T, size_t size >
istream &operator>>( istream &input, Array< T, size > &a )
{
   for ( int i = 0; i < size; i++ )
      input >> a.ptr[ i ];

   return input; // enables cin >> x >> y;
} // end function 

template < class T, size_t size >
ostream &operator<<( ostream &output, const Array< T, size > &a )
{
   int i;

   for ( i = 0; i < size; i++ )
   {
      output << setw( 12 ) << a.ptr[ i ];

      if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
         output << endl;
   } // end for

   if ( i % 4 != 0 ) // end last line of output
      output << endl;

   return output; // enables cout << x << y;
} // end function operator<<
#endif
